#include <gloox/client.h>
#include <gloox/disco.h>
#include <gloox/connectionlistener.h>
#include <gloox/mucroom.h>
#include <gloox/message.h>
#include <gloox/mucroomhandler.h>
#include <gloox/connectionlistener.h>
//#include <gloox/connectionhttpproxy.h>
//#include <gloox/connectiontcpclient.h>
using namespace gloox;

#include <iostream>
#include <string>
#include <fstream>
#include <vector>
using namespace std;

#include <dlfcn.h>
#include <unistd.h>
#include <sys/types.h>
#include <dirent.h>
#include <string.h>
#include <stdlib.h>
#include "modules/BaseModule.h"


class Bot: public gloox::ConnectionListener, gloox::MUCRoomHandler
{
	public:
		Bot();
		virtual ~Bot();
		void Connect();

	private:
		gloox::Client *client;
		gloox::MUCRoom *room;
		string JabberID, JabberPass, ConfID;
		vector <string> modulesName;
		void *handle;
		BaseModule *module;
		create_m * create_mod;
		create_mm * create_mmod;
		destroy_m * destroy_mod;
		
		void config();	
	
	protected:	
		
		void onConnect();
		void onDisconnect(gloox::ConnectionError e);
		void handleMUCMessage (MUCRoom *room, const Message &msg, bool priv);	
		
				
	 	bool onTLSConnect(const gloox::CertInfo&){return true;}
		void handleMUCParticipantPresence(gloox::MUCRoom*, gloox::MUCRoomParticipant, const gloox::Presence&){}
		bool handleMUCRoomCreation(gloox::MUCRoom*){ return true;}
		void handleMUCSubject(gloox::MUCRoom*, const std::string&, const std::string&){}
		void handleMUCInviteDecline(gloox::MUCRoom*, const gloox::JID&, const std::string&){}
		void handleMUCError(gloox::MUCRoom*, gloox::StanzaError){}
		void handleMUCInfo(gloox::MUCRoom*, int, const std::string&, const gloox::DataForm*){}
		void handleMUCItems(gloox::MUCRoom*, const std::list<gloox::Disco::Item*, std::allocator<gloox::Disco::Item*> >&){}
};

void Bot::handleMUCMessage (MUCRoom *room, const Message &msg, bool priv)
{
	char buf[256] = "";
	string str;
	int length;

	if(!msg.when())
	{
		for (unsigned int i = 0; i < modulesName.size(); ++i)
		{
			str = "." + string(modulesName[i]);
			length = str.length();
			if(!msg.body().compare(0, length, str + " ", 0, length) || (msg.body() == str))
			{
				unsigned int j;
				
				string temp = modulesName[i];
				strncat(buf, "./modules/", 10);
				for (j = 10; j < temp.length() + 10; ++j)
					buf[j] = temp[j-10];
				
				buf[j + 1] = '\0';
				strncat(buf, ".so", 3); 	
				handle = dlopen(buf, RTLD_LAZY);

				if (!handle)
				{
					cerr << "Cannot load library: " << dlerror() << endl;
					exit(1);
				}
				dlerror();
				destroy_mod = (destroy_m*) dlsym(handle, "destroy");
				if (msg.body() == str)
				{
					create_mmod = (create_mm*) dlsym(handle, "ccreate");
					module = create_mmod();
				}
				else
				{
					create_mod = (create_m*) dlsym(handle, "create");
					module = create_mod(msg.body().substr(length + 1));
				}
				room->send(module->showAnswer());
				destroy_mod(module);
				dlclose(handle);

			}
		}
	
		if (msg.body() == ".plugins")
		{
			string str = "";
			for(unsigned int i = 0; i < modulesName.size(); ++i)
				str += "* " + modulesName[i] + "\n";

			room->send(str);
		}
		if(!msg.body().compare(0, 9, "пошел вон!", 0, 9))
			room->send("А по морде не хо?");
		
		if(msg.body() == ".exit")
			exit(1);
	}
	
}

Bot::Bot()
{
	DIR *dir = opendir("modules/");
    string str;
	if(dir)
    {
        struct dirent *ent;
        while((ent = readdir(dir)) != NULL)
        {
			if (strstr(ent->d_name, ".so"))
			{
				cout << "Loading " <<  ent->d_name << endl;
            	modulesName.push_back(string(ent->d_name).substr(0, string(ent->d_name).length() - 3));
			}
        }
    }
	
	config();

	client = new gloox::Client(std::string(JabberID), std::string(JabberPass));

	client->disableRoster();

	client->setPresence(gloox::Presence::Available, -1);

	client->disco()->setVersion("ignoBot", "0.1.2alpha", "");
	client->disco()->setIdentity("Simple", "Bot");

	client->setCompression(false);
	client->registerConnectionListener(this);
}

Bot::~Bot()
{
	delete client;
	delete room;
}

void Bot::config()
{
	ifstream inFile("config", ios::in);
	
	getline(inFile, JabberID);
	getline(inFile, JabberPass);
	getline(inFile, ConfID);

	JabberID = JabberID.substr(JabberID.find_first_of("\"") + 1, JabberID.rfind("\"") - JabberID.find_first_of("\"") - 1 );
	JabberPass = JabberPass.substr(JabberPass.find_first_of("\"") + 1, JabberPass.rfind("\"") - JabberPass.find_first_of("\"") - 1 );
	ConfID = ConfID.substr(ConfID.find_first_of("\"") + 1, ConfID.rfind("\"") - ConfID.find_first_of("\"") - 1 );

}

void Bot::Connect()
{
	client->connect();
}


void Bot::onConnect()
{
	cout << "Connected" << endl;
	room = new gloox::MUCRoom( client, std::string(ConfID), 0, 0 );

	room->join();	
	room->registerMUCRoomHandler(this);
}

void Bot::onDisconnect( gloox::ConnectionError e )
{
	cout << " Disconnected, error: " << e << endl;
}

int main()
{
	Bot myBot;
	myBot.Connect();

	return 0;
}
